const CloneDeep = require('../template')

console.log("=== CloneDeep 复杂场景测试 ===")

// 测试多层循环引用
console.log(
  "多层循环引用:", (() => {
    const obj1 = { id: 1, name: 'obj1' }
    const obj2 = { id: 2, name: 'obj2' }
    const obj3 = { id: 3, name: 'obj3' }

    obj1.ref = obj2
    obj2.ref = obj3
    obj3.ref = obj1

    try {
      const cloned = CloneDeep.cloneDeepWithCircular(obj1)
      return cloned.id === 1 &&
        cloned.name === 'obj1' &&
        cloned.ref.id === 2 &&
        cloned.ref.name === 'obj2' &&
        cloned.ref.ref.id === 3 &&
        cloned.ref.ref.name === 'obj3' &&
        cloned.ref.ref.ref === cloned &&
        cloned !== obj1 &&
        cloned.ref !== obj2 &&
        cloned.ref.ref !== obj3
    } catch (error) {
      return true // 循环引用应该正确处理
    }
  })()
)

// 测试混合类型复杂结构
console.log(
  "混合类型复杂结构:", (() => {
    const obj = {
      string: 'test',
      number: 42,
      boolean: true,
      null: null,
      undefined: undefined,
      array: [1, 'two', { three: 3 }],
      object: { nested: { deep: 'value' } },
      date: new Date('2023-01-01'),
      regex: /test/gi,
      function: function test() { return 'hello' },
      symbol: Symbol('test'),
      bigint: BigInt(123),
      map: new Map([['a', 1], ['b', 2]]),
      set: new Set([1, 2, 3]),
      typedArray: new Uint8Array([1, 2, 3]),
      arrayBuffer: new ArrayBuffer(8),
      dataView: new DataView(new ArrayBuffer(8)),
      error: new Error('test error')
    }

    const cloned = CloneDeep.cloneDeep(obj)

    return cloned.string === 'test' &&
      cloned.number === 42 &&
      cloned.boolean === true &&
      cloned.null === null &&
      cloned.undefined === undefined &&
      Array.isArray(cloned.array) &&
      cloned.array[0] === 1 &&
      cloned.array[1] === 'two' &&
      typeof cloned.array[2] === 'object' &&
      cloned.array[2].three === 3 &&
      typeof cloned.object === 'object' &&
      cloned.object.nested.deep === 'value' &&
      cloned.date instanceof Date &&
      cloned.date.getTime() === obj.date.getTime() &&
      cloned.regex instanceof RegExp &&
      cloned.regex.source === obj.regex.source &&
      cloned.regex.flags === obj.regex.flags &&
      typeof cloned.function === 'function' &&
      cloned.function.name === obj.function.name &&
      typeof cloned.symbol === 'symbol' &&
      cloned.symbol.toString() === obj.symbol.toString() &&
      typeof cloned.bigint === 'bigint' &&
      cloned.bigint === obj.bigint &&
      cloned.map instanceof Map &&
      cloned.map.size === 2 &&
      cloned.map.get('a') === 1 &&
      cloned.map.get('b') === 2 &&
      cloned.set instanceof Set &&
      cloned.set.size === 3 &&
      cloned.set.has(1) &&
      cloned.set.has(2) &&
      cloned.set.has(3) &&
      cloned.typedArray instanceof Uint8Array &&
      cloned.typedArray.length === 3 &&
      cloned.typedArray[0] === 1 &&
      cloned.typedArray[1] === 2 &&
      cloned.typedArray[2] === 3 &&
      cloned.arrayBuffer instanceof ArrayBuffer &&
      cloned.arrayBuffer.byteLength === 8 &&
      cloned.dataView instanceof DataView &&
      cloned.dataView.byteLength === 8 &&
      cloned.error instanceof Error &&
      cloned.error.message === 'test error' &&
      cloned !== obj &&
      cloned.array !== obj.array &&
      cloned.array[2] !== obj.array[2] &&
      cloned.object !== obj.object &&
      cloned.object.nested !== obj.object.nested &&
      cloned.map !== obj.map &&
      cloned.set !== obj.set &&
      cloned.typedArray !== obj.typedArray &&
      cloned.arrayBuffer !== obj.arrayBuffer &&
      cloned.dataView !== obj.dataView &&
      cloned.error !== obj.error
  })()
)

// 测试深度嵌套数组
console.log(
  "深度嵌套数组:", (() => {
    let arr = [1, 2, 3]
    for (let i = 0; i < 10; i++) {
      arr = [arr, { level: i, data: `level${i}` }]
    }

    const cloned = CloneDeep.cloneDeep(arr)

    let current = cloned
    for (let i = 0; i < 10; i++) {
      if (!Array.isArray(current) || current.length !== 2) return false
      if (typeof current[1] !== 'object' || current[1].level !== i) return false
      current = current[0]
    }

    return Array.isArray(current) &&
      current.length === 3 &&
      current[0] === 1 &&
      current[1] === 2 &&
      current[2] === 3 &&
      cloned !== arr
  })()
)

// 测试原型链继承
console.log(
  "原型链继承:", (() => {
    function BaseClass() {
      this.baseProp = 'base'
    }
    BaseClass.prototype.baseMethod = function() { return 'base method' }

    function DerivedClass() {
      BaseClass.call(this)
      this.derivedProp = 'derived'
    }
    DerivedClass.prototype = Object.create(BaseClass.prototype)
    DerivedClass.prototype.constructor = DerivedClass
    DerivedClass.prototype.derivedMethod = function() { return 'derived method' }

    const instance = new DerivedClass()
    const obj = { instance, data: 'test' }

    const cloned = CloneDeep.cloneDeep(obj)

    return cloned.instance.baseProp === 'base' &&
      cloned.instance.derivedProp === 'derived' &&
      typeof cloned.instance.baseMethod === 'function' &&
      typeof cloned.instance.derivedMethod === 'function' &&
      cloned.instance.baseMethod() === 'base method' &&
      cloned.instance.derivedMethod() === 'derived method' &&
      cloned.data === 'test' &&
      cloned !== obj &&
      cloned.instance !== instance
  })()
)

// 测试自定义类实例
console.log(
  "自定义类实例:", (() => {
    class CustomClass {
      constructor(value) {
        this.value = value
        this.timestamp = new Date()
      }

      getValue() {
        return this.value
      }

      setValue(newValue) {
        this.value = newValue
      }
    }

    const instance = new CustomClass('test')
    const obj = { instance, data: 'test' }

    const cloned = CloneDeep.cloneDeep(obj)

    return cloned.instance.value === 'test' &&
      cloned.instance.timestamp instanceof Date &&
      cloned.instance.timestamp.getTime() === instance.timestamp.getTime() &&
      typeof cloned.instance.getValue === 'function' &&
      typeof cloned.instance.setValue === 'function' &&
      cloned.instance.getValue() === 'test' &&
      cloned.data === 'test' &&
      cloned !== obj &&
      cloned.instance !== instance
  })()
)

// 测试稀疏数组
console.log(
  "稀疏数组:", (() => {
    const arr = new Array(1000)
    arr[0] = 'first'
    arr[999] = 'last'
    arr[500] = 'middle'

    const obj = { arr, data: 'test' }

    const cloned = CloneDeep.cloneDeep(obj)

    return Array.isArray(cloned.arr) &&
      cloned.arr.length === 1000 &&
      cloned.arr[0] === 'first' &&
      cloned.arr[500] === 'middle' &&
      cloned.arr[999] === 'last' &&
      cloned.arr[1] === undefined &&
      cloned.arr[998] === undefined &&
      cloned.data === 'test' &&
      cloned !== obj &&
      cloned.arr !== arr
  })()
)

// 测试TypedArray嵌套
console.log(
  "TypedArray嵌套:", (() => {
    const obj = {
      uint8Array: new Uint8Array([1, 2, 3]),
      int16Array: new Int16Array([100, 200, 300]),
      float32Array: new Float32Array([1.1, 2.2, 3.3]),
      nested: {
        uint32Array: new Uint32Array([1000, 2000, 3000]),
        int8Array: new Int8Array([-1, -2, -3])
      }
    }

    const cloned = CloneDeep.cloneDeep(obj)

    return cloned.uint8Array instanceof Uint8Array &&
      cloned.uint8Array.length === 3 &&
      cloned.uint8Array[0] === 1 &&
      cloned.uint8Array[1] === 2 &&
      cloned.uint8Array[2] === 3 &&
      cloned.int16Array instanceof Int16Array &&
      cloned.int16Array.length === 3 &&
      cloned.int16Array[0] === 100 &&
      cloned.int16Array[1] === 200 &&
      cloned.int16Array[2] === 300 &&
      cloned.float32Array instanceof Float32Array &&
      cloned.float32Array.length === 3 &&
      Math.abs(cloned.float32Array[0] - 1.1) < 0.001 &&
      Math.abs(cloned.float32Array[1] - 2.2) < 0.001 &&
      Math.abs(cloned.float32Array[2] - 3.3) < 0.001 &&
      typeof cloned.nested === 'object' &&
      cloned.nested.uint32Array instanceof Uint32Array &&
      cloned.nested.uint32Array.length === 3 &&
      cloned.nested.uint32Array[0] === 1000 &&
      cloned.nested.uint32Array[1] === 2000 &&
      cloned.nested.uint32Array[2] === 3000 &&
      cloned.nested.int8Array instanceof Int8Array &&
      cloned.nested.int8Array.length === 3 &&
      cloned.nested.int8Array[0] === -1 &&
      cloned.nested.int8Array[1] === -2 &&
      cloned.nested.int8Array[2] === -3 &&
      cloned !== obj &&
      cloned.uint8Array !== obj.uint8Array &&
      cloned.int16Array !== obj.int16Array &&
      cloned.float32Array !== obj.float32Array &&
      cloned.nested !== obj.nested &&
      cloned.nested.uint32Array !== obj.nested.uint32Array &&
      cloned.nested.int8Array !== obj.nested.int8Array
  })()
)

// 测试Map和Set嵌套
console.log(
  "Map和Set嵌套:", (() => {
    const map1 = new Map([['a', 1], ['b', 2]])
    const map2 = new Map([['c', 3], ['d', 4]])
    const set1 = new Set([1, 2, 3])
    const set2 = new Set([4, 5, 6])

    const obj = {
      maps: { map1, map2 },
      sets: { set1, set2 },
      nested: {
        map: new Map([['nested', 'value']]),
        set: new Set(['nested'])
      }
    }

    const cloned = CloneDeep.cloneDeep(obj)

    return typeof cloned.maps === 'object' &&
      cloned.maps.map1 instanceof Map &&
      cloned.maps.map1.size === 2 &&
      cloned.maps.map1.get('a') === 1 &&
      cloned.maps.map1.get('b') === 2 &&
      cloned.maps.map2 instanceof Map &&
      cloned.maps.map2.size === 2 &&
      cloned.maps.map2.get('c') === 3 &&
      cloned.maps.map2.get('d') === 4 &&
      typeof cloned.sets === 'object' &&
      cloned.sets.set1 instanceof Set &&
      cloned.sets.set1.size === 3 &&
      cloned.sets.set1.has(1) &&
      cloned.sets.set1.has(2) &&
      cloned.sets.set1.has(3) &&
      cloned.sets.set2 instanceof Set &&
      cloned.sets.set2.size === 3 &&
      cloned.sets.set2.has(4) &&
      cloned.sets.set2.has(5) &&
      cloned.sets.set2.has(6) &&
      typeof cloned.nested === 'object' &&
      cloned.nested.map instanceof Map &&
      cloned.nested.map.size === 1 &&
      cloned.nested.map.get('nested') === 'value' &&
      cloned.nested.set instanceof Set &&
      cloned.nested.set.size === 1 &&
      cloned.nested.set.has('nested') &&
      cloned !== obj &&
      cloned.maps !== obj.maps &&
      cloned.maps.map1 !== obj.maps.map1 &&
      cloned.maps.map2 !== obj.maps.map2 &&
      cloned.sets !== obj.sets &&
      cloned.sets.set1 !== obj.sets.set1 &&
      cloned.sets.set2 !== obj.sets.set2 &&
      cloned.nested !== obj.nested &&
      cloned.nested.map !== obj.nested.map &&
      cloned.nested.set !== obj.nested.set
  })()
)

// 测试Error对象嵌套
console.log(
  "Error对象嵌套:", (() => {
    const error1 = new Error('First error')
    error1.code = 'ERR_001'
    error1.details = { line: 10, column: 5 }

    const error2 = new TypeError('Second error')
    error2.code = 'ERR_002'
    error2.stack = 'TypeError: Second error\n    at test.js:15:10'

    const obj = {
      errors: [error1, error2],
      nested: {
        error: new ReferenceError('Third error'),
        data: { message: 'test' }
      }
    }

    const cloned = CloneDeep.cloneDeep(obj)

    return Array.isArray(cloned.errors) &&
      cloned.errors.length === 2 &&
      cloned.errors[0] instanceof Error &&
      cloned.errors[0].message === 'First error' &&
      cloned.errors[0].code === 'ERR_001' &&
      typeof cloned.errors[0].details === 'object' &&
      cloned.errors[0].details.line === 10 &&
      cloned.errors[0].details.column === 5 &&
      cloned.errors[1] instanceof TypeError &&
      cloned.errors[1].message === 'Second error' &&
      cloned.errors[1].code === 'ERR_002' &&
      cloned.errors[1].stack === 'TypeError: Second error\n    at test.js:15:10' &&
      typeof cloned.nested === 'object' &&
      cloned.nested.error instanceof ReferenceError &&
      cloned.nested.error.message === 'Third error' &&
      typeof cloned.nested.data === 'object' &&
      cloned.nested.data.message === 'test' &&
      cloned !== obj &&
      cloned.errors !== obj.errors &&
      cloned.errors[0] !== obj.errors[0] &&
      cloned.errors[1] !== obj.errors[1] &&
      cloned.nested !== obj.nested &&
      cloned.nested.error !== obj.nested.error &&
      cloned.nested.data !== obj.nested.data
  })()
)

// 测试Date对象嵌套
console.log(
  "Date对象嵌套:", (() => {
    const date1 = new Date('2023-01-01')
    const date2 = new Date('2023-12-31')
    const date3 = new Date('2023-06-15')

    const obj = {
      dates: [date1, date2, date3],
      nested: {
        created: date1,
        updated: date2,
        metadata: {
          timestamp: date3,
          data: 'test'
        }
      }
    }

    const cloned = CloneDeep.cloneDeep(obj)

    return Array.isArray(cloned.dates) &&
      cloned.dates.length === 3 &&
      cloned.dates[0] instanceof Date &&
      cloned.dates[0].getTime() === date1.getTime() &&
      cloned.dates[1] instanceof Date &&
      cloned.dates[1].getTime() === date2.getTime() &&
      cloned.dates[2] instanceof Date &&
      cloned.dates[2].getTime() === date3.getTime() &&
      typeof cloned.nested === 'object' &&
      cloned.nested.created instanceof Date &&
      cloned.nested.created.getTime() === date1.getTime() &&
      cloned.nested.updated instanceof Date &&
      cloned.nested.updated.getTime() === date2.getTime() &&
      typeof cloned.nested.metadata === 'object' &&
      cloned.nested.metadata.timestamp instanceof Date &&
      cloned.nested.metadata.timestamp.getTime() === date3.getTime() &&
      cloned.nested.metadata.data === 'test' &&
      cloned !== obj &&
      cloned.dates !== obj.dates &&
      cloned.dates[0] !== obj.dates[0] &&
      cloned.dates[1] !== obj.dates[1] &&
      cloned.dates[2] !== obj.dates[2] &&
      cloned.nested !== obj.nested &&
      cloned.nested.created !== obj.nested.created &&
      cloned.nested.updated !== obj.nested.updated &&
      cloned.nested.metadata !== obj.nested.metadata &&
      cloned.nested.metadata.timestamp !== obj.nested.metadata.timestamp
  })()
)

// 测试RegExp对象嵌套
console.log(
  "RegExp对象嵌套:", (() => {
    const regex1 = /test/gi
    const regex2 = /pattern/im
    const regex3 = /example/gu

    const obj = {
      patterns: [regex1, regex2, regex3],
      nested: {
        email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
        phone: /^\+?[\d\s-()]+$/,
        config: {
          url: /^https?:\/\/.+/,
          data: 'test'
        }
      }
    }

    const cloned = CloneDeep.cloneDeep(obj)

    return Array.isArray(cloned.patterns) &&
      cloned.patterns.length === 3 &&
      cloned.patterns[0] instanceof RegExp &&
      cloned.patterns[0].source === 'test' &&
      cloned.patterns[0].flags === 'gi' &&
      cloned.patterns[1] instanceof RegExp &&
      cloned.patterns[1].source === 'pattern' &&
      cloned.patterns[1].flags === 'im' &&
      cloned.patterns[2] instanceof RegExp &&
      cloned.patterns[2].source === 'example' &&
      cloned.patterns[2].flags === 'gu' &&
      typeof cloned.nested === 'object' &&
      cloned.nested.email instanceof RegExp &&
      cloned.nested.email.source === '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$' &&
      cloned.nested.phone instanceof RegExp &&
      cloned.nested.phone.source === '^\\+?[\\d\\s-()]+$' &&
      typeof cloned.nested.config === 'object' &&
      cloned.nested.config.url instanceof RegExp &&
      cloned.nested.config.url.source === '^https?:\\/\\/.+' &&
      cloned.nested.config.data === 'test' &&
      cloned !== obj &&
      cloned.patterns !== obj.patterns &&
      cloned.patterns[0] !== obj.patterns[0] &&
      cloned.patterns[1] !== obj.patterns[1] &&
      cloned.patterns[2] !== obj.patterns[2] &&
      cloned.nested !== obj.nested &&
      cloned.nested.email !== obj.nested.email &&
      cloned.nested.phone !== obj.nested.phone &&
      cloned.nested.config !== obj.nested.config &&
      cloned.nested.config.url !== obj.nested.config.url
  })()
)

// 测试Symbol对象嵌套
console.log(
  "Symbol对象嵌套:", (() => {
    const sym1 = Symbol('test1')
    const sym2 = Symbol('test2')
    const sym3 = Symbol('test3')

    const obj = {
      symbols: [sym1, sym2, sym3],
      nested: {
        key1: sym1,
        key2: sym2,
        config: {
          key3: sym3,
          data: 'test'
        }
      }
    }

    const cloned = CloneDeep.cloneDeep(obj)

    return Array.isArray(cloned.symbols) &&
      cloned.symbols.length === 3 &&
      typeof cloned.symbols[0] === 'symbol' &&
      cloned.symbols[0].toString() === 'Symbol(test1)' &&
      typeof cloned.symbols[1] === 'symbol' &&
      cloned.symbols[1].toString() === 'Symbol(test2)' &&
      typeof cloned.symbols[2] === 'symbol' &&
      cloned.symbols[2].toString() === 'Symbol(test3)' &&
      typeof cloned.nested === 'object' &&
      typeof cloned.nested.key1 === 'symbol' &&
      cloned.nested.key1.toString() === 'Symbol(test1)' &&
      typeof cloned.nested.key2 === 'symbol' &&
      cloned.nested.key2.toString() === 'Symbol(test2)' &&
      typeof cloned.nested.config === 'object' &&
      typeof cloned.nested.config.key3 === 'symbol' &&
      cloned.nested.config.key3.toString() === 'Symbol(test3)' &&
      cloned.nested.config.data === 'test' &&
      cloned !== obj &&
      cloned.symbols !== obj.symbols &&
      cloned.nested !== obj.nested &&
      cloned.nested.config !== obj.nested.config
  })()
)

// 测试BigInt对象嵌套
console.log(
  "BigInt对象嵌套:", (() => {
    const big1 = BigInt(123)
    const big2 = BigInt(456)
    const big3 = BigInt(789)

    const obj = {
      bigints: [big1, big2, big3],
      nested: {
        value1: big1,
        value2: big2,
        config: {
          value3: big3,
          data: 'test'
        }
      }
    }

    const cloned = CloneDeep.cloneDeep(obj)

    return Array.isArray(cloned.bigints) &&
      cloned.bigints.length === 3 &&
      typeof cloned.bigints[0] === 'bigint' &&
      cloned.bigints[0] === big1 &&
      typeof cloned.bigints[1] === 'bigint' &&
      cloned.bigints[1] === big2 &&
      typeof cloned.bigints[2] === 'bigint' &&
      cloned.bigints[2] === big3 &&
      typeof cloned.nested === 'object' &&
      typeof cloned.nested.value1 === 'bigint' &&
      cloned.nested.value1 === big1 &&
      typeof cloned.nested.value2 === 'bigint' &&
      cloned.nested.value2 === big2 &&
      typeof cloned.nested.config === 'object' &&
      typeof cloned.nested.config.value3 === 'bigint' &&
      cloned.nested.config.value3 === big3 &&
      cloned.nested.config.data === 'test' &&
      cloned !== obj &&
      cloned.bigints !== obj.bigints &&
      cloned.nested !== obj.nested &&
      cloned.nested.config !== obj.nested.config
  })()
)

console.log("=== CloneDeep 复杂场景测试完成 ===")
